/*
 * MainWindow.java
 *
 * Created on December 16, 2007, 3:17 PM
 * 
 * @author Team KARP
 */

package protovitae.ui;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.io.File;
import javax.swing.DefaultComboBoxModel;
import javax.swing.DefaultListModel;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextPane;
import protovitae.data.*;

public class MainWindow extends javax.swing.JFrame {
    private DefaultListModel traitlist = new DefaultListModel(); //The two lists in the organism editor.
    private DefaultComboBoxModel exposedattributes = new DefaultComboBoxModel(); //The list of exposed attributes present in the trait editor.
    private Simulation mysim = null;
    private ConcreteOrganism currentsel; //The currently selected organism
    private ConcreteOrganism tempmake; //Temporary organism that we're currently making for adding.
    
    /** Creates new form MainWindow */
    public MainWindow() {
        initComponents();
        initPosition();
        ((EnvironmentView)pnlEnvironment).addGLEventListener((EnvironmentView)pnlEnvironment); //Make the GL panel work.
        mysim = new Simulation(((EnvironmentView)pnlEnvironment));
        ((EnvironmentView)pnlEnvironment).setSimulation(mysim);
        
        //Make a temporary organism for editing, before it gets added to the simulation.
        tempmake = new ConcreteOrganism(mysim);
        ConcreteGene gene = new ConcreteGene(tempmake);
        tempmake.addGene(gene);
        ((TraitEditorPanel)pnlTraitEditor).setEdit(gene);
        ((OrganismEditorPanel)pnlOrganismEditor).setEdit(tempmake); //Order is important here, because it won't show up if we add it before it exists!
        ((OrganismEditorPanel)pnlOrganismEditor).setTraitpanel((TraitEditorPanel)pnlTraitEditor); //Allow right click menu in organism editor to affect this window
        ((OrganismEditorPanel)pnlOrganismEditor).initTree(); //Populate the tree
    }
    
    /** Creates new form MainWindow, with an existing simulation */
    public MainWindow(File simpath) {
        initComponents();
        initPosition();
        ((EnvironmentView)pnlEnvironment).addGLEventListener((EnvironmentView)pnlEnvironment); //Make the GL panel work.
        mysim = Simulation.loadSim(((EnvironmentView)pnlEnvironment),simpath);
        ((EnvironmentView)pnlEnvironment).setSimulation(mysim);
        
        //Make a temporary organism for editing, before it gets added to the simulation.
        tempmake = new ConcreteOrganism(mysim);
        ConcreteGene gene = new ConcreteGene(tempmake);
        tempmake.addGene(gene);
        ((TraitEditorPanel)pnlTraitEditor).setEdit(gene);
        ((OrganismEditorPanel)pnlOrganismEditor).setEdit(tempmake); //Order is important here, because it won't show up if we add it before it exists!
        ((OrganismEditorPanel)pnlOrganismEditor).setTraitpanel((TraitEditorPanel)pnlTraitEditor); //Allow right click menu in organism editor to affect this window
        ((OrganismEditorPanel)pnlOrganismEditor).initTree(); //Populate the tree
    }
    
    private void initPosition() {
        this.setSize(1000, 900);
        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
        setLocation(screenSize.width / 2 - (this.getWidth() / 2), screenSize.height / 2 - (this.getHeight() / 2));
    }
    
    /** Populate the exposed attribute list. */
    private void populateList() {
        for(int i=0; i<Organism.ATTRIBUTE_TYPE.values().length; i++) {
            getExposedattributes().addElement(Organism.ATTRIBUTE_TYPE.values()[i].toString());
        }
    }
    
    public void updateTraitTree() {
        ((OrganismEditorPanel)this.pnlOrganismEditor).updateTraitTree();
    }
    
    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        pnlOuter = new javax.swing.JPanel();
        splWindowInterior = new javax.swing.JSplitPane();
        pnlControl = new javax.swing.JPanel();
        tabMain = new javax.swing.JTabbedPane();
        pnlOrganismEditor = new OrganismEditorPanel(this);
        pnlTraitEditor = new TraitEditorPanel(this);
        pnlEnvironmentPadding = new javax.swing.JPanel();
        spltEnvironment = new javax.swing.JSplitPane();
        pnlInformation = new javax.swing.JPanel();
        tabInformation = new javax.swing.JTabbedPane();
        pnlProgramInformation = new javax.swing.JScrollPane();
        txtProgramInformation = new javax.swing.JTextPane();
        pnlSystemInformation = new javax.swing.JScrollPane();
        txtSystemInformation = new javax.swing.JTextPane();
        pnlEnvironment = new EnvironmentView(this);
        barOrganismActions = new javax.swing.JToolBar();
        btnAddOrganism = new javax.swing.JButton();
        btnEditOrganism = new javax.swing.JButton();
        btnDeleteOrganism = new javax.swing.JButton();
        btnRun = new javax.swing.JButton();
        btnStep = new javax.swing.JButton();
        btnStop = new javax.swing.JButton();
        lblSpeed = new javax.swing.JLabel();
        sldSpeed = new javax.swing.JSlider();
        pnlStatusPane = new javax.swing.JPanel();
        lblStatusPlaceHolder = new javax.swing.JLabel();
        lblStatus = new javax.swing.JLabel();
        mnuBar = new javax.swing.JMenuBar();
        mnuFile = new javax.swing.JMenu();
        mnuSaveSimulation = new javax.swing.JMenuItem();
        mnuFileSep = new javax.swing.JSeparator();
        mnuExit = new javax.swing.JMenuItem();
        mnuEdit = new javax.swing.JMenu();
        mnuEditCut = new javax.swing.JMenuItem();
        mnuEditCopy = new javax.swing.JMenuItem();
        mnuEditPaste = new javax.swing.JMenuItem();
        mnuTraits = new javax.swing.JMenu();
        mnuTraitsNew = new javax.swing.JMenuItem();
        mnuDuplicateOrganism = new javax.swing.JMenuItem();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        setTitle("ProtoVitae - Simulation View");

        pnlOuter.setLayout(new java.awt.BorderLayout());

        splWindowInterior.setDividerLocation(300);
        splWindowInterior.setEnabled(false);

        pnlControl.setLayout(new java.awt.BorderLayout());

        tabMain.addTab("Organism Editor", pnlOrganismEditor);
        tabMain.addTab("Trait Editor", pnlTraitEditor);

        pnlControl.add(tabMain, java.awt.BorderLayout.CENTER);

        splWindowInterior.setRightComponent(pnlControl);

        pnlEnvironmentPadding.setMinimumSize(new java.awt.Dimension(500, 0));
        pnlEnvironmentPadding.setPreferredSize(new java.awt.Dimension(100, 100));
        pnlEnvironmentPadding.setLayout(new java.awt.BorderLayout());

        spltEnvironment.setDividerLocation(300);
        spltEnvironment.setOrientation(javax.swing.JSplitPane.VERTICAL_SPLIT);
        spltEnvironment.setEnabled(false);
        spltEnvironment.setPreferredSize(new java.awt.Dimension(100, 100));

        pnlInformation.setPreferredSize(new java.awt.Dimension(100, 100));
        pnlInformation.setLayout(new java.awt.BorderLayout());

        tabInformation.setPreferredSize(new java.awt.Dimension(100, 100));

        pnlProgramInformation.setBorder(javax.swing.BorderFactory.createTitledBorder("Information Console"));
        pnlProgramInformation.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
        pnlProgramInformation.setPreferredSize(new java.awt.Dimension(100, 100));

        txtProgramInformation.setBackground(new java.awt.Color(0, 0, 0));
        txtProgramInformation.setContentType("text/html");
        txtProgramInformation.setEditable(false);
        txtProgramInformation.setForeground(new java.awt.Color(102, 255, 103));
        txtProgramInformation.setText("<html>\r\n  <head>\r\n\r\t<style>body {foreground-color: green;}</style>\n  </head>\r\n  <body color=\"green\">\r\n    <h2>Ready</h2>    \n    <p style=\"margin-top: 0\">\r\n    The simulation is ready to be used. Select an organism for more information.\n    </p>\r\n  </body>\r\n</html>\r\n");
        txtProgramInformation.setAutoscrolls(false);
        txtProgramInformation.setMaximumSize(new java.awt.Dimension(102, 62));
        pnlProgramInformation.setViewportView(txtProgramInformation);

        tabInformation.addTab("Simulation Information", pnlProgramInformation);

        pnlSystemInformation.setBorder(javax.swing.BorderFactory.createTitledBorder("Information Console"));

        txtSystemInformation.setBackground(new java.awt.Color(0, 0, 0));
        txtSystemInformation.setContentType("text/html");
        txtSystemInformation.setForeground(new java.awt.Color(51, 204, 0));
        txtSystemInformation.setText("<html>\r\n  <head>\r\n\r\t<style>body {foreground-color: green;}</style>\n  </head>\r\n  <body color=\"green\">\r\n    <h2>Ready</h2>    \n<p style=\"margin-top: 0\">\r\n      Your system is capable of running this software.\n    </p>\r\n  </body>\r\n</html>\r\n");
        pnlSystemInformation.setViewportView(txtSystemInformation);

        tabInformation.addTab("System Information", pnlSystemInformation);

        pnlInformation.add(tabInformation, java.awt.BorderLayout.CENTER);

        spltEnvironment.setRightComponent(pnlInformation);
        spltEnvironment.setLeftComponent(pnlEnvironment);

        pnlEnvironmentPadding.add(spltEnvironment, java.awt.BorderLayout.CENTER);

        splWindowInterior.setLeftComponent(pnlEnvironmentPadding);

        pnlOuter.add(splWindowInterior, java.awt.BorderLayout.CENTER);

        getContentPane().add(pnlOuter, java.awt.BorderLayout.CENTER);

        barOrganismActions.setRollover(true);

        btnAddOrganism.setText("Add organism");
        btnAddOrganism.setFocusable(false);
        btnAddOrganism.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        btnAddOrganism.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
        btnAddOrganism.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnAddOrganismActionPerformed(evt);
            }
        });
        barOrganismActions.add(btnAddOrganism);

        btnEditOrganism.setText("Edit organism");
        btnEditOrganism.setFocusable(false);
        btnEditOrganism.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        btnEditOrganism.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
        btnEditOrganism.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnEditOrganismActionPerformed(evt);
            }
        });
        barOrganismActions.add(btnEditOrganism);

        btnDeleteOrganism.setText("Delete organism");
        btnDeleteOrganism.setFocusable(false);
        btnDeleteOrganism.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        btnDeleteOrganism.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
        btnDeleteOrganism.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnDeleteOrganismActionPerformed(evt);
            }
        });
        barOrganismActions.add(btnDeleteOrganism);

        btnRun.setText("Run Simulation");
        btnRun.setFocusable(false);
        btnRun.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        btnRun.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
        btnRun.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnRunActionPerformed(evt);
            }
        });
        barOrganismActions.add(btnRun);

        btnStep.setText("Pause/Step simulation");
        btnStep.setEnabled(false);
        btnStep.setFocusable(false);
        btnStep.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        btnStep.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
        btnStep.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnStepActionPerformed(evt);
            }
        });
        barOrganismActions.add(btnStep);

        btnStop.setText("End simulation");
        btnStop.setEnabled(false);
        btnStop.setFocusable(false);
        btnStop.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        btnStop.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
        btnStop.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnStopActionPerformed(evt);
            }
        });
        barOrganismActions.add(btnStop);

        lblSpeed.setText("Speed:");
        barOrganismActions.add(lblSpeed);

        sldSpeed.setMajorTickSpacing(25);
        sldSpeed.setMaximum(200);
        sldSpeed.setMinorTickSpacing(5);
        sldSpeed.setPaintLabels(true);
        sldSpeed.setPaintTicks(true);
        sldSpeed.setValue(100);
        sldSpeed.addChangeListener(new javax.swing.event.ChangeListener() {
            public void stateChanged(javax.swing.event.ChangeEvent evt) {
                sldSpeedStateChanged(evt);
            }
        });
        barOrganismActions.add(sldSpeed);

        getContentPane().add(barOrganismActions, java.awt.BorderLayout.PAGE_START);

        pnlStatusPane.setBorder(javax.swing.BorderFactory.createEtchedBorder());
        pnlStatusPane.setLayout(new java.awt.BorderLayout());
        pnlStatusPane.add(lblStatusPlaceHolder, java.awt.BorderLayout.CENTER);

        lblStatus.setText("Welcome to ProtoVitae!");
        pnlStatusPane.add(lblStatus, java.awt.BorderLayout.EAST);

        getContentPane().add(pnlStatusPane, java.awt.BorderLayout.PAGE_END);

        mnuFile.setText("File");

        mnuSaveSimulation.setText("Save Simulation");
        mnuSaveSimulation.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                mnuSaveSimulationPerformed(evt);
            }
        });
        mnuFile.add(mnuSaveSimulation);
        mnuFile.add(mnuFileSep);

        mnuExit.setText("Exit");
        mnuExit.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                mnuExitActionPerformed(evt);
            }
        });
        mnuFile.add(mnuExit);

        mnuBar.add(mnuFile);

        mnuEdit.setText("Edit");

        mnuEditCut.setText("Cut");
        mnuEditCut.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                mnuEditCutActionPerformed(evt);
            }
        });
        mnuEdit.add(mnuEditCut);

        mnuEditCopy.setText("Copy");
        mnuEditCopy.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                mnuEditCopyActionPerformed(evt);
            }
        });
        mnuEdit.add(mnuEditCopy);

        mnuEditPaste.setText("Paste");
        mnuEditPaste.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                mnuEditPasteActionPerformed(evt);
            }
        });
        mnuEdit.add(mnuEditPaste);

        mnuBar.add(mnuEdit);

        mnuTraits.setText("Advanced");

        mnuTraitsNew.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_T, java.awt.event.InputEvent.CTRL_MASK));
        mnuTraitsNew.setText("New Stock Trait...");
        mnuTraitsNew.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                mnuTraitsNewActionPerformed(evt);
            }
        });
        mnuTraits.add(mnuTraitsNew);

        mnuDuplicateOrganism.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_D, java.awt.event.InputEvent.CTRL_MASK));
        mnuDuplicateOrganism.setText("Duplicate Organism");
        mnuDuplicateOrganism.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                mnuDuplicateOrganismActionPerformed(evt);
            }
        });
        mnuTraits.add(mnuDuplicateOrganism);

        mnuBar.add(mnuTraits);

        setJMenuBar(mnuBar);

        pack();
    }// </editor-fold>//GEN-END:initComponents
    
    private void btnRunActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnRunActionPerformed
        if(mysim.isAlive()) //isAlive is inherited from Thread
            mysim.resumeSim();
        else{
            if(((OrganismEditorPanel)pnlOrganismEditor).getEditing() == currentsel)
                ((OrganismEditorPanel)pnlOrganismEditor).setEdit(tempmake);
            mysim.start();
            
            //Remove editing ability
            barOrganismActions.remove(btnEditOrganism);
            barOrganismActions.remove(btnDeleteOrganism);
            btnAddOrganism.setEnabled(true);
            barOrganismActions.revalidate(); //Re-layout the toolbar.
        }
        //Update button states
        btnStep.setEnabled(true);
        btnStop.setEnabled(true);
        btnRun.setEnabled(false);
        lblStatus.setText("Running...");
}//GEN-LAST:event_btnRunActionPerformed

    private void mnuTraitsNewActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_mnuTraitsNewActionPerformed
       String retval = JOptionPane.showInputDialog("Enter a name for the new trait:");
       if(retval != null){
           ConcreteGene temp1 = new ConcreteGene(null);
           temp1.setName(retval);
           mysim.getMasterlist().addStockTrait(temp1);
           TraitEditorFrame tedit = new TraitEditorFrame(this);
           tedit.getPanel().setEdit(temp1);
           tedit.setVisible(true);
           ((OrganismEditorPanel)pnlOrganismEditor).updateTraitTree();
       }
}//GEN-LAST:event_mnuTraitsNewActionPerformed

    /** Add an organism to the simulation **/
    private void btnAddOrganismActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnAddOrganismActionPerformed
        if(mysim.addOrganism(tempmake)){
            tempmake = new ConcreteOrganism(mysim);
            ConcreteGene gene = new ConcreteGene(tempmake);
            tempmake.addGene(gene);
            ((TraitEditorPanel)pnlTraitEditor).setEdit(gene);
            ((OrganismEditorPanel)pnlOrganismEditor).setEdit(tempmake);
            ((OrganismEditorPanel)pnlOrganismEditor).updateTraitTree(); //Add this organism to the tree.
        }
        else{
            JOptionPane.showMessageDialog(this, "The simulation is too full.");
        }
    }//GEN-LAST:event_btnAddOrganismActionPerformed

    private void btnDeleteOrganismActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnDeleteOrganismActionPerformed
        if(((OrganismEditorPanel)pnlOrganismEditor).getEditing() == currentsel){
            ((OrganismEditorPanel)pnlOrganismEditor).setEdit(tempmake); //Switch back to what we were
            btnAddOrganism.setEnabled(true);
        }
        mysim.getOrganisms().remove(currentsel);
        currentsel = null;
        ((OrganismEditorPanel)pnlOrganismEditor).updateTraitTree(); //Update the trait tree
    }//GEN-LAST:event_btnDeleteOrganismActionPerformed

    private void sldSpeedStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_sldSpeedStateChanged
        mysim.setCycleLength(250+200-sldSpeed.getValue()*2);
        //This makes 50ms, or 20fps the fastest possible speed, and 250 the default.
        //However, 0 is 450 ms, which is just under 2fps. We may want to tweak this later.
    }//GEN-LAST:event_sldSpeedStateChanged

    private void btnStepActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnStepActionPerformed
        mysim.pauseSim(); //Kill the thread, if it isn't already. Otherwise, step
        
        lblStatus.setText("Simulation paused.");
        
        //Update button states
        btnRun.setEnabled(true);
    }//GEN-LAST:event_btnStepActionPerformed

    private void btnStopActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnStopActionPerformed
        mysim.endSim();
    }//GEN-LAST:event_btnStopActionPerformed

    private void mnuExitActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_mnuExitActionPerformed
        this.dispose(); //Make File->Exit work
        System.exit(0); //Force program to die.
    }//GEN-LAST:event_mnuExitActionPerformed

    private void btnEditOrganismActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnEditOrganismActionPerformed
        if(currentsel != null){
            if(((OrganismEditorPanel)pnlOrganismEditor).getEditing() == currentsel){
                btnAddOrganism.setEnabled(true);
                ((OrganismEditorPanel)pnlOrganismEditor).setEdit(tempmake);
            }
            else{
                //Notify the organism editor
                ((OrganismEditorPanel)pnlOrganismEditor).setEdit(currentsel);
                btnAddOrganism.setEnabled(false);
            }
            ((OrganismEditorPanel)pnlOrganismEditor).updateTraitTree(); //Update the trait tree.
        }
    }//GEN-LAST:event_btnEditOrganismActionPerformed

    private void mnuEditCutActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_mnuEditCutActionPerformed
        ((TraitEditorPanel)pnlTraitEditor).cut();
    }//GEN-LAST:event_mnuEditCutActionPerformed

    private void mnuEditCopyActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_mnuEditCopyActionPerformed
        ((TraitEditorPanel)pnlTraitEditor).copy();
    }//GEN-LAST:event_mnuEditCopyActionPerformed

    private void mnuEditPasteActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_mnuEditPasteActionPerformed
        ((TraitEditorPanel)pnlTraitEditor).paste();
    }//GEN-LAST:event_mnuEditPasteActionPerformed

    private void mnuSaveSimulationPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_mnuSaveSimulationPerformed
        JFileChooser chooser = new JFileChooser();
        FileXMLFilter filter = new FileXMLFilter();
        chooser.setFileFilter(filter);
        chooser.setDialogTitle("Select a file save location");
        chooser.setApproveButtonText("Save");
        int returnVal = chooser.showOpenDialog(this);
        if (returnVal == JFileChooser.APPROVE_OPTION) {
            if(!chooser.getSelectedFile().getAbsolutePath().toLowerCase().endsWith(".xml")) //Sanity fix
                chooser.setSelectedFile(new File(chooser.getSelectedFile().getAbsolutePath().concat(".xml")));
            this.mysim.saveSim(chooser.getSelectedFile());
        }
    }//GEN-LAST:event_mnuSaveSimulationPerformed

    private void mnuDuplicateOrganismActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_mnuDuplicateOrganismActionPerformed
        if(currentsel != null){
            mysim.addOrganism(new ConcreteOrganism(this.currentsel,mysim));

            ((OrganismEditorPanel)pnlOrganismEditor).updateTraitTree(); //Add this organism to the tree.     
        }
    }//GEN-LAST:event_mnuDuplicateOrganismActionPerformed

    public void printToSystemLog(String logMessage) {
        this.txtSystemInformation.setText(this.txtSystemInformation.getText() + "<br>" + logMessage);
    }
    
    /** Validate the Move action **/

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JToolBar barOrganismActions;
    private javax.swing.JButton btnAddOrganism;
    private javax.swing.JButton btnDeleteOrganism;
    private javax.swing.JButton btnEditOrganism;
    private javax.swing.JButton btnRun;
    private javax.swing.JButton btnStep;
    private javax.swing.JButton btnStop;
    private javax.swing.JLabel lblSpeed;
    private javax.swing.JLabel lblStatus;
    private javax.swing.JLabel lblStatusPlaceHolder;
    private javax.swing.JMenuBar mnuBar;
    private javax.swing.JMenuItem mnuDuplicateOrganism;
    private javax.swing.JMenu mnuEdit;
    private javax.swing.JMenuItem mnuEditCopy;
    private javax.swing.JMenuItem mnuEditCut;
    private javax.swing.JMenuItem mnuEditPaste;
    private javax.swing.JMenuItem mnuExit;
    private javax.swing.JMenu mnuFile;
    private javax.swing.JSeparator mnuFileSep;
    private javax.swing.JMenuItem mnuSaveSimulation;
    private javax.swing.JMenu mnuTraits;
    private javax.swing.JMenuItem mnuTraitsNew;
    private javax.swing.JPanel pnlControl;
    private java.awt.Canvas pnlEnvironment;
    private javax.swing.JPanel pnlEnvironmentPadding;
    private javax.swing.JPanel pnlInformation;
    private javax.swing.JPanel pnlOrganismEditor;
    private javax.swing.JPanel pnlOuter;
    private javax.swing.JScrollPane pnlProgramInformation;
    private javax.swing.JPanel pnlStatusPane;
    private javax.swing.JScrollPane pnlSystemInformation;
    private javax.swing.JPanel pnlTraitEditor;
    private javax.swing.JSlider sldSpeed;
    private javax.swing.JSplitPane splWindowInterior;
    private javax.swing.JSplitPane spltEnvironment;
    private javax.swing.JTabbedPane tabInformation;
    private javax.swing.JTabbedPane tabMain;
    private javax.swing.JTextPane txtProgramInformation;
    private javax.swing.JTextPane txtSystemInformation;
    // End of variables declaration//GEN-END:variables

    public void setStats(ConcreteOrganism organism) {
        ExposedAttribute health = organism.getAttribute(Organism.ATTRIBUTE_TYPE.HEALTH);
        ExposedAttribute age = organism.getAttribute(Organism.ATTRIBUTE_TYPE.AGE);
        ExposedAttribute attraction = organism.getAttribute(Organism.ATTRIBUTE_TYPE.ATTRACTION);
        ExposedAttribute brawn = organism.getAttribute(Organism.ATTRIBUTE_TYPE.BRAWN);
        ExposedAttribute caution = organism.getAttribute(Organism.ATTRIBUTE_TYPE.CAUTION);
        ExposedAttribute fortitude = organism.getAttribute(Organism.ATTRIBUTE_TYPE.FORTITUDE);
        ExposedAttribute action = organism.getAttribute(Organism.ATTRIBUTE_TYPE.ACTION);
        Color color = organism.getColor();
        int red = color.getRed();
        int green = color.getGreen();
        int blue = color.getBlue();
        StringBuilder builder = new StringBuilder();
        
        builder.append("<html><head><style>body {foreground-color: green;}</style></head><body color=\"green\">");
        builder.append("Id: ");
        builder.append(organism.myId);
        builder.append("<br />");
        
        builder.append("Red: ");
        builder.append(red);
        builder.append("<br />");
        
        builder.append("Green: ");
        builder.append(green);
        builder.append("<br />");
        
        builder.append("Blue: ");
        builder.append(blue);
        builder.append("<br />");
        
        builder.append("Health: ");
        builder.append(health.getCurrent());
        builder.append(" / ");
        builder.append(health.getMax());
        builder.append("<br />");
        builder.append("Age: ");
        builder.append(age.getCurrent());
        builder.append(" / ");
        builder.append(age.getMax());
        builder.append("<br />");
        builder.append("Attraction: ");
        builder.append(attraction.getCurrent());
        builder.append(" / ");
        builder.append(attraction.getMax());
        builder.append("<br />");
        builder.append("Brawn: ");
        builder.append(brawn.getCurrent());
        builder.append(" / ");
        builder.append(brawn.getMax());
        builder.append("<br />");
        builder.append("Caution: ");
        builder.append(caution.getCurrent());
        builder.append(" / ");
        builder.append(caution.getMax());
        builder.append("<br />");
        builder.append("Fortitude: ");
        builder.append(fortitude.getCurrent());
        builder.append(" / ");
        builder.append(fortitude.getMax());
        builder.append("<br />");
        builder.append("Action: ");
        builder.append(action.getCurrent());
        builder.append(" / ");
        builder.append(action.getMax());
        builder.append("<br /><br />");
        builder.append("Genetic Code: ");
        builder.append(wrap(organism.getGeneticInformation()));
        
        
        
        builder.append("</body></html>");
        
        this.txtProgramInformation.setText(builder.toString());
    }
    
    private String wrap(String str) {
        final int wrapColumn = 35;
        StringBuilder builder = new StringBuilder();
        int last = 0;
        int i;
        for (i = 0; i < str.length(); ++i) {
            if (i % wrapColumn == 0) {
                builder.append(str.substring(last, i));
                builder.append("<br />");
                last = i;
            }
        }
        builder.append(str.substring(last, str.length()));
        return builder.toString();
    }
    
    public DefaultListModel getTraitlist() {
        return traitlist;
    }

    public void setTraitlist(DefaultListModel traitlist) {
        this.traitlist = traitlist;
    }

    public DefaultComboBoxModel getExposedattributes() {
        return exposedattributes;
    }

    public void setExposedattributes(DefaultComboBoxModel exposedattributes) {
        this.exposedattributes = exposedattributes;
    }

    /** Get the current simulation */
    public Simulation getSimulation() {
        return mysim;
    }
    
    /** Notify the main window that an organism is selected. **/
    public void notifySelection(ConcreteOrganism org){
        //Update various windows here.
        currentsel = org;
        
    }

    /** Get the currently selected organism **/
    public ConcreteOrganism getSelectedOrganism() {
        return currentsel;
    }
    
    /** End the simulation and display the report **/
    public void endSimulation(){
        //Update button states
        btnStep.setEnabled(false);
        btnStop.setEnabled(false);
        btnRun.setEnabled(false); //Prevent user from running again, because we'd need to dispose of the simulation instance to call mysim.start();
        btnAddOrganism.setEnabled(false);
        btnDeleteOrganism.setEnabled(false);
        lblStatus.setText("The simulation is complete.");
        
        JTextPane tpne = new JTextPane();
        String report = "The simulation is over.\n\n";
        tabMain.removeAll();
        tabMain.add("Results",tpne);
        
        report = report.concat("Total cycles: " + mysim.getNumCycles() + "\n");
        report = report.concat("Organisms added: " + mysim.getNumAdded() + "\n");
        report = report.concat("Organisms deleted: " + mysim.getNumDeleted() + "\n");
        report = report.concat("Total deaths: " + mysim.getNumDeaths() + "\n\n");
        report = report.concat("Thank you for using ProtoVitae!");
        tpne.setText(report);
    }
    
    /** Switch to a particular tab in this window, if it exists **/
    public void switchTab(JPanel thetab){
        try{
            tabMain.setSelectedComponent(thetab);
        }
        catch(Exception ex){
            System.out.println("Attempted to auto-switch to a tab that doesn't exist.");
        }
    }
}
